﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

using agree.schema;

using alib.BitArray;
using alib.Collections.ReadOnly;
using alib.Debugging;
using alib.Enumerable;
using alib.Reflection;
using alib.String;

namespace agree.transfer.old
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DisplayName("Surface transfer")]
	public class SurfaceStringTransfer : identity_base
	{
		public SurfaceStringTransfer(IIdentity prv, SrcTgtGrammar stg)
			: base(prv)
		{
			this.stg = stg;
		}

		public readonly SrcTgtGrammar stg;

		public StringItem Produce(StringItem item_in)
		{
			/// get tokenizers for source and target
			ITokenizer tok_src, tok_tgt;

			tok_src = (ITokenizer)P.Tokenizer.GetValue(stg.Source.Grammar);
			tok_tgt = (ITokenizer)P.Tokenizer.GetValue(stg.Target.Grammar);

			/// tokenize source string 
			var ts_src = new TokenizedString(null, item_in.Text, tok_src);

			/// get tokenized string transfer controller
			var tst = stg.tok_str_xfer;

			/// do transfer
			var ts_tgt = tst.Produce(ts_src);

			/// assemble target surface string from workds using target tokenizer
			String s_tgt = tok_tgt.MakeSurface(ts_tgt.Select(w => w.Text));

			/// wrap in an agree object
			return new StringItem(this, s_tgt);
		}
	};

	public class TokenizedStringSet : IdentList<TokenizedString>
	{
		public TokenizedStringSet(IIdentity prv)
			: base(prv)
		{
		}
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DisplayName("Tokenized string transfer")]
	public class TokenizedStringTransfer : identity_base//, ρParser.IDirect, ρGenerator.IDirect
	{
		public TokenizedStringTransfer(IIdentity prv, SrcTgtGrammar stg)
			: base(prv)
		{
			this.stg = stg;
		}

		public readonly SrcTgtGrammar stg;

		public TokenizedStringSet Produce(TokenizedString item_in)
		{
			//Parser parser = stg.Source.Grammar.parser;
			//Generator gen = stg.Target.Grammar.generator;

			//IActiveTask<ParseControl> parse_task = parser.Produce(item_in);

			//IDerivation src_drv = stg.Source.Grammar.Get<ParseSelector>().Produce(parse_task.Result).First();

			//Mrs.Mrs src_mrs = src_drv.Tfs.Mrs;

			//TransferMrs src_tmrs = new TransferMrs(src_mrs);

			//TransferControl ctrl = stg.Produce(src_tmrs);

			//TransferMrs tgt_tmrs = ctrl.Result;

			//IActiveTask<GenControl> gen_task = gen.Produce(tgt_tmrs.Mrs);

			//return gen_task.Result.ResultStrings;
			return null;
		}

		//Parser parser;
		//Parser ρParser.IDirect.Value
		//{
		//	get { return this.parser; }
		//	set { this.parser = value; }
		//}

		//Generator gen;
		//Generator ρGenerator.IDirect.Value
		//{
		//	get { return this.gen; }
		//	set { this.gen = value; }
		//}
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	public class TransferHypothesis : identity_base
	{
		public TransferHypothesis(IIdentity prv, TransferGrammar tg, Object mrs, int numInputRels)
			: base(prv)
		{
			this.tg = tg;
			//this.mrs = mrs;
			flags = new System.Collections.BitArray[numInputRels];
			for (int i = 0; i < flags.Length; i++)
				flags[i] = new System.Collections.BitArray(tg.flag_name_map.Count);
		}

		public TransferHypothesis(IIdentity prv, TransferGrammar tg, Object mrs, System.Collections.BitArray[] copyFlags)
			: base(prv)
		{
			this.tg = tg;
			//this.mrs = mrs;
			flags = (BitArray[])copyFlags.Clone();
		}
		//public readonly agree.Mrs.Mrs mrs;
		/* hypothesis instance flags... */
		public System.Collections.BitArray[] flags;
		TransferGrammar tg;
		//MultiRootTfs ttfs;
		//TransferControl ctrl;
	};

	public class RelMemory
	{
		public TfsSlot In;
		public bool f_was;
	};

	public class InOutRelLabelPair : RelMemory
	{
		public TfsSlot Out;
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// pertaining to a single semantic transfer operation
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DisplayName("Transfer control")]
	public class TransferControl : identity_base// ControlBase
	{
		public TransferControl(IIdentity trace, SrcTgtGrammar stg, TransferMrs input_mrs)
			: base(trace)//, stg.Source.Grammar.glc.jc)
		{
#if OLDMRS
			this.input_mrs = input_mrs;
#endif
			this.stg = stg;
		}

		SrcTgtGrammar stg;

#if OLDMRS
		TransferMrs input_mrs;
		TransferMrs result_mrs;

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public TransferMrs RootFunc()
		{
			var initial_hyp = new TransferHypothesis(this, stg, null, input_mrs.MrsRels.Length);

			Queue<TransferHypothesis> hypotheses = new Queue<TransferHypothesis>();
			List<TransferHypothesis> finished_hypos = new List<TransferHypothesis>();

			while (hypotheses.Count > 0)
			{
				TransferHypothesis cur_h = hypotheses.Dequeue();
				foreach (TransferRule rule in stg.rules)
				{
					//find source permutations with correct flags.

					//find valid target permutations

					//foreach (permutation combination)
					{


						TransferHypothesis new_h = UnificationResult(cur_h.mrs, cur_h.flags);
						//new_h.

						//new_h.flags = cur_h.flags.UnionWith(/*rule.flags*/ new HashSet<>());

						if (new_h != null)
						{
							if (false /*check flags for all-done*/ )
							{
								finished_hypos.Add(new_h);
							}
							else
							{
								hypotheses.Enqueue(new_h);
							}
						}
					}
				}
			}
			return default(TransferMrs);
		}
#if false
		List<TfsSlot<TransferRule>> FlattenRuleSourceRels(TransferRule tr, int side)
		{
			List<TfsSlot<TransferRule>> result = new List<TfsSlot<TransferRule>>();
			HashSet<int> deleted_idx = new HashSet<int>();
			HashSet<int> was_out = new HashSet<int>();

			//TODO: check that IsSource is still appropriate		
			var combine_rels = tr.Where(r => r.tagged_rel_mode.IsSource)
								.GroupBy(r => tr.relLabels[r.ix1 - 1])
								.Where(g => g.Key.Length > 0).ToArray();

			var combine_rels_unif = combine_rels.Select(g => {
									var ga = g.ToArray();
									deleted_idx.Add(Math.Max(ga[0].ix1 - 1, ga[1].ix1 - 1));
									was_out.Add(Math.Min(ga[0].ix1 - 1, ga[1].ix1 - 1));
									return new Pairing<int>(ga[0].ix1 - 1, ga[1].ix1 - 1);
										});
			//var u = Unification._s_init(tr.tg[side].tm, Tfs.Flags.None);
			
			RelsTfs reduced_rule = Unification.ReduceRels(tr, combine_rels_unif);
			var new_label_array = new string[tr.relLabels.Length - deleted_idx.Count];

			int write_idx = 0;
			for (int read_idx = 0; read_idx < tr.Count; read_idx++)
			{
				if (!deleted_idx.Contains(read_idx))
				{
					if (was_out.Contains(read_idx))
					{
						was_out.Remove(read_idx);
						was_out.Add(write_idx);
					}
					new_label_array[write_idx++] = tr.relLabels[read_idx];
					
				}
			}

			var io_rel_groups = reduced_rule.Where(r => r.tagged_rel_mode.IsTarget)
								.GroupBy(r => new_label_array[r.ix1 - 1])
								.Where(g => g.Key.Length > 0).ToArray();

			List<RelMemory> source_rels = new List<RelMemory>();
			List<InOutRelLabelPair> target_rel_pairs = new List<InOutRelLabelPair>();

			foreach (var rel in reduced_rule.Where(r => r.tagged_rel_mode.IsSource))
			{
				RelMemory relmem = new RelMemory();
				relmem.In = rel;
				relmem.f_was = was_out.Contains(rel.ix1 - 1);
				source_rels.Add(relmem);
			}

			foreach (var irg in io_rel_groups)
			{
				var irga = irg.ToArray();

				if (irga.Length != 2)
					Nop.X();

				InOutRelLabelPair iorlp = new InOutRelLabelPair();

				if (irga[0].tagged_rel_mode.IsInRel)
				{
					iorlp.In = irga[0];
					iorlp.Out = irga[1];
				}
				else
				{
					iorlp.In = irga[1];
					iorlp.Out = irga[0];
				}

				target_rel_pairs.Add(iorlp);
			}
			
			
			return null;
		}
#endif
		TransferHypothesis UnificationResult(Mrs.Mrs mrs, System.Collections.BitArray[] inFlags)
		{
			return new TransferHypothesis(this, this.stg, mrs, inFlags);
		}
#endif


		bool initial_check_source_ep(TfsSlot inp_rel, TfsSlot rule_rel, BitArray hyp_flags)
		{
			/*foreach (int rf in rule_rel.tfs.req_flags[rule_rel.ix1 - 1])
				if (!hyp_flags.Get(rf))
					return false;

			foreach (int ef in rule_rel.tfs.ex_flags[rule_rel.ix1 - 1])
				if (hyp_flags.Get(ef))
					return false;*/
			TypeUtils tu = null;
			MrsManager mrsm = null;
			int _dont_need;
			Edge.Flag f_rule = rule_rel.tfs.TryGetFlagsMark(mrsm.ifeat_pred, rule_rel.out_mark, out _dont_need);
			Edge.Flag f_inp = inp_rel.tfs.TryGetFlagsMark(mrsm.ifeat_pred, inp_rel.out_mark, out _dont_need);

			if (!tu.QuickTypeSubsumeCheck(f_rule, f_inp))
				return false; // it failed.

			Edge.Flag f_rule_a0 = rule_rel.tfs.TryGetFlagsMark(mrsm.ifeat_arg0, rule_rel.out_mark, out _dont_need);
			Edge.Flag f_inp_a0 = inp_rel.tfs.TryGetFlagsMark(mrsm.ifeat_arg0, inp_rel.out_mark, out _dont_need);

			if (!tu.QuickTypeSubsumeCheck(f_rule_a0, f_inp_a0))
				return false; // it failed.

			return true;
		}

		bool initial_check_target_ep(TfsSlot hyp_rel, TfsSlot rule_rel)
		{


			return true;
		}

#if false
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		void _unify_transfer_rels(SrcTgtRelsTfs tfs_inp, TransferRule rule, SrcTgtRelsTfs tfs_hyp)
		{
			pinfo* pi_rul = _init_tfs(rule);
			pinfo* pi_inp = _init_tfs(tfs_inp);
			pinfo* pi_hyp = _init_tfs(tfs_hyp);

			var rul_rels = rule.Select(ts => new UnifierRelRoot(pi_rul, ts));

			var hyp_rels = tfs_hyp.Select(ts => new UnifierRelRoot(pi_hyp, ts));

			var out_rels = rul_rels.Where(a => a.RelMode == RelMode.TargetOut);

			var permutations = rul_rels
								.Where(a => a.IsSource)
								.Select(x => new RelMatch(x, tfs_inp.Select(ts => new UnifierRelRoot(pi_inp, ts))))
								.GroupCrossProduct();

			foreach (var perm in permutations)
			{
				bool need_reset = false;

				foreach (var match in perm)
				{
					if (!subsumes(match.x, match.y))
						goto next_perm;
				}

				need_reset = true;

				foreach (var match in perm)
				{
					if (!_duplex_node(match.x, match.y))
						goto next_perm;
				}

				resolve_priority_maps(rule);

				make_snapshot();

				var tgt_perms = rul_rels
								.Where(a => a.RelMode == RelMode.TargetIn)
								.Select(x => new RelMatch(x, hyp_rels))
								.GroupCrossProduct();

				foreach (var t_perm in tgt_perms)
				{
					restore_snapshot();

					foreach (var t_match in t_perm)
					{
						if (!_duplex_node(t_match.x, t_match.y))
							goto next_tgt_perm;
					}


					var roots = hyp_rels
									.Where(a => a.RelMode == RelMode.TargetOut)
									.Concat(out_rels)
									.Select(a => a.uix);

					RelsTfs h_new = _emit_roots_to_rels_tfs(roots);

				next_tgt_perm: ;
				}

			next_perm:
				if (need_reset)
					next_gen();
			}
		}
#endif
		void next_gen()
		{
		}

		void make_snapshot()
		{
		}

		void restore_snapshot()
		{
		}

		bool check_hypothesis_complete()
		{
			return false;
		}

		void prep_a_root(int uix, TransferRelMode trm)
		{
		}

		void resolve_priority_maps(MultiRootTfs rule)
		{
		}
	};
}
